package com.order.service;

import com.alibaba.fastjson.JSONObject;
import com.order.entity.OrderEntity;
import com.order.repository.OrderRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.util.Date;
import java.util.UUID;

@Service
@Slf4j
public class OrderService implements RabbitTemplate.ConfirmCallback, RabbitTemplate.ReturnCallback {

    @Resource
    private OrderRepository orderRepository;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
     * 基于MQ发送投递订单消息
     */
    @Transactional
    public String sendOrder() {
        // 1.先创建我们订单信息
        String orderId = UUID.randomUUID().toString();
        OrderEntity orderEntity = new OrderEntity("name:"+System.currentTimeMillis(),new Date(),123.0,0,3L, orderId);
        // 2.添加到我们的数据库中
        OrderEntity result = orderRepository.save(orderEntity);
        if (ObjectUtils.isEmpty(result)) {
            return "下单失败";
        }
        // 3.订单数据库插入成功的情况下, 使用MQ异步发送派单信息
        String msgJson = JSONObject.toJSONString(orderEntity);
        sendMsg(msgJson);
        int i = 1/0;   //创建订单出现异常，但派单消息已经发出，需要进行补单操作
        return orderId;
    }

    private void sendMsg(String msgJson) {
        // 设置生产者消息确认机制
        this.rabbitTemplate.setMandatory(true);
        this.rabbitTemplate.setConfirmCallback(this);
        CorrelationData correlationData = new CorrelationData();
        correlationData.setId(msgJson);
        String orderExchange = "order_exchange_name";
        String orderRoutingKey = "orderRoutingKey";
        rabbitTemplate.convertAndSend(orderExchange, orderRoutingKey, msgJson, correlationData);
    }

    /**
     * correlationData 投递失败回调的消息
     *
     * @param correlationData
     * @param ack             true 投递到MQ成功 如果是为false情况下 消息投递失败
     * @param cause
     */
    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
        String msg = correlationData.getId();
        if (!ack) {
            log.info("<<<往MQ投递消息失败>>>>:" + msg);
            // 采用递归算法重试
            sendMsg(msg);
            return;
        }
        log.info("<<<往MQ投递消息成功>>>>:" + msg);
        // 生产者投递多次还是is的情况下应该 人工记录
    }
    @Override
    public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
        System.out.println("return--message:" + new String(message.getBody()) + ",replyCode:" + replyCode
                + ",replyText:" + replyText + ",exchange:" + exchange + ",routingKey:" + routingKey);
    }

    /**
     * 总结下就是：
     *
     * 如果消息没有到exchange,则confirm回调,ack=false
     *
     * 如果消息到达exchange,则confirm回调,ack=true
     *
     * exchange到queue成功,则不回调return
     *
     * exchange到queue失败,则回调return(需设置mandatory=true,否则不回回调,消息就丢了)
     * ————————————————
     * 版权声明：本文为CSDN博主「gmHappy」的原创文章，遵循 CC 4.0 BY-SA 版权协议，转载请附上原文出处链接及本声明。
     * 原文链接：https://blog.csdn.net/ctwy291314/java/article/details/80534604
     */
}
